public class uploadCASController {
    List<Lead> Leads = new List<lead>();
    
    public List<lead> getLeads(){
        return Leads;
    }

    public PageReference processUpload() {
        if(fileName.contains('csv')){
            try{List<Lead> updatedLeads = updateCASresults();
            }
            catch(Exception e){
                ApexPages.addMessages(e);
            }
        }else{
            fileBody = Blob.valueOf(''); // Set the file body to empty since it's not the right file
            ApexPages.Message myMsg = new ApexPages.Message(ApexPages.Severity.FATAL, 'This page can only accept csv files');
            ApexPages.addMessage(myMsg);
        }
        return null;
    }
    
    private Blob fileBody;
    private String fileName;
    private Integer fileSize;
    String[] Rows = new String[]{};
    
    public String getFileName()
    {
        return this.fileName;
    }
    
    public void setFileName(String fileName)
    {
        this.fileName = fileName;
    }
    
    public Blob getFileBody()
    {
        return this.fileBody;
    }
    
    public void setFileBody(Blob fileBody)
    {
        this.fileBody = fileBody;
        setFileSize(this.fileBody.size());
    }
    
    public Integer getFileSize()
    {
        return this.fileSize;
    }

    public void setFileSize(Integer fileSize)
    {
        this.fileSize = fileSize;
    }
    
    public string[] getContents(){
        return fileBody.toString().split('\n');
    }
    
    public List<Lead> updateCASresults(){
        // Map File Contents to string
        
        Rows = fileBody.toString().split('[\n\r]');
        
        // Find the title row
        String[] Headings = new List<String>();
        String[] Row = new List<String>();
        while(Headings.size()==0&&Rows.size()>0){
            Row = Rows[0].split(',');
            if(Row.size()>0){
                if(Row[0].trim()=='Company Name') Headings = Row;
                else Rows.remove(0);
            }else Rows.remove(0);
        }
        
        // Capture order of column headings
        Map<String,Integer> HeadingIndex = new Map<String,Integer>();
        for(Integer i = 0;i<Headings.size();i++){
            HeadingIndex.put(Headings[i].trim(),i);
        }
        
        System.Debug('HeadingIndex: '+HeadingIndex);
        
        // Generate a Map of Data to update
        Map<Id,String> Dispositions = new Map<Id,String>();
       
        for(integer i=1;i<Rows.size();i++){
            List<String> Cols = cleanRow(Rows[i]).split(',');
            if(Cols.size()>=HeadingIndex.get('CRM ID')){
                Id LeadId = Cols[HeadingIndex.get('CRM ID')];
                Dispositions.put(LeadId,Cols[HeadingIndex.get('Disposition')]);
            }
        }
        
        System.Debug('Dispositions: '+Dispositions);
        
        // Query Leads
        Set<Id> LeadIDs = Dispositions.keyset();
        Leads = [select Name,Company,Lead_Status__c, Bad_Data_Explanation__c, Phone_Verified__c from lead where Id in :LeadIDs];
  
 
        if(Leads.size()>0){
                    
            // Compare values and update Leads
            for(Lead l : Leads){
                if(Dispositions.get(l.Id)=='Information Error'){
                    l.Lead_Status__c = 'Bad Data';
                    l.Bad_Data_Explanation__c = 'Wrong Number';
                }else if(Dispositions.get(l.Id)=='Person Left'){
                    l.Lead_Status__c = 'No Longer at Company';
                }else if(Dispositions.get(l.Id)=='Person Left REM'){
                    l.Lead_Status__c = 'No Longer at Company';
                }else if(Dispositions.get(l.Id)=='Not Available'){
                    l.Phone_Verified__c = date.today();
                }else if(Dispositions.get(l.Id)=='Direct Number'){
                    if(l.Lead_Status__c == 'Unverified') l.Lead_Status__c = 'New';
                    l.Phone_Verified__c = date.today();
                }else if(Dispositions.get(l.Id)=='Voicemail Dropped'){
                    l.Phone_Verified__c = date.today();
                    if(l.Lead_Status__c == 'New' || l.Lead_Status__c == 'Unverified') l.Lead_Status__c='Touched';
                }else if(Dispositions.get(l.Id)=='Voicemail Reached'){
                    l.Phone_Verified__c = date.today();
                }else if(Dispositions.get(l.Id)=='Do Not Call'){
                    l.Lead_Status__c = 'Do Not Call';
                }else if(Dispositions.get(l.Id)=='GateKeeper Block'){
                    l.Phone_Verified__c = date.today();
                }else if(Dispositions.get(l.Id)=='GateKeeper Block REM'){
                    l.Lead_Status__c = 'Not Interested';
                }
           
            }
            update Leads;
            }
        return Leads;
    }
    
    public string cleanRow(String row){
        
               if(row.contains('$')) row = row.replace('$','');
               
               // Remove internal commas
               pattern myPattern = pattern.compile('(".*?")');
               Matcher myMatcher = myPattern.matcher(row);
               while(myMatcher.find()){
                   if(myMatcher.group().startsWith('"')) row = row.replace(myMatcher.group(),myMatcher.group().replace('"','').replace(',',''));
               }
               return row;
    }
    
    static testMethod void basicTest(){
        
        // Initiate Visualforce Page
        PageReference pageRef = Page.uploadCAS;
        Test.setCurrentPage(pageRef);

        uploadCASController controller = new uploadCASController();
        
        list<Lead> TestLeads = new List<lead>();
        for(integer i=0;i<10;i++){
            TestLeads.add(new Lead(FirstName='Test', LastName='Lead '+i, Company='Company', Lead_Status__c = 'New'));
        }
        insert TestLeads;
        String csvText = '';
        csvText += 'Line 1,2 \n Line 2,3 \n Line 3,4 \n';
        csvText += 'Company Name, CRM ID, Disposition \n';
        Map<String,Id> testDispositions = new Map<String,Id>();
        List<String> Dispositions = new List<string>{'Information Error', 'Wrong Number', 'Person Left','Person Left REM', 'Not Available', 'Voicemail Dropped', 'Voicemail Reached',
            'Do Not Call', 'Gatekeeper Block', 'Gatekeeper Block REM'};
        for(Integer i=0;i<TestLeads.size();i++){
          string Disposition = Dispositions[math.mod(i,Dispositions.size())];
            csvText += 'ABC Company,' + TestLeads[i].Id + ',' + Disposition + '\n';
            testDispositions.put(Disposition,TestLeads[i].Id);
            System.Debug('Adding value for Lead ' +TestLeads[i].Id +' of ' +Disposition);
        }
        controller.setFileName('Test.csv');
        controller.setFileBody(blob.valueOf(csvText));
        
        System.debug('CSV Text: '+csvText);
        
        // Process Fake Upload
        PageReference result = controller.processUpload();
        
        // Check values for Information Error, Person Left, Not Available, Voicemail Reached
        Lead InformationError = [select Lead_Status__c, Bad_Data_Explanation__c, Phone_Verified__c from Lead where Id = :testDispositions.get('Information Error') limit 1];
        System.Debug('Status for Lead ' + InformationError.Id +' is ' + InformationError.Lead_Status__c);
        System.AssertEquals('Bad Data', InformationError.Lead_Status__c);
    }
    
}